#include<iostream>//Prim算法实现最小生成树
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int>P;
typedef vector<vector<P>>Graph;
struct edge{
    int from,to,weight;
};
struct cmp{
    bool operator()(const edge&a,const edge&b)
    {
        return a.weight>b.weight;
    }
};
vector<edge> Prim(Graph &G,int s)
{
    int n=G.size();
    vector<edge>MST;
    vector<bool>is_inMST(n,false);
    vector<int>dist(n,INT_MAX);
    dist[s]=0;
    priority_queue<edge,vector<edge>,cmp>Q;
    Q.push(edge{s,s,0});
    while(!Q.empty())
    {
        int from=Q.top().from,to=Q.top().to,weight=Q.top().weight;
        Q.pop();
        if(is_inMST[to])continue;
        if(weight!=0)MST.push_back(edge{from,to,weight});
        is_inMST[to]=true;
        for(auto neighbor:G[to])
        {
            int v=neighbor.first,w=neighbor.second;
            if(dist[v]>w&&!is_inMST[v])
            {
                dist[v]=w;
                Q.push(edge{to,v,w});
            }
        }
    }
    return MST;
}
int main()
{
    int n,m;
    cin>>n>>m;
    vector<edge>E(m);
    Graph G(n);
    for(int i=0;i<m;i++)
    {
        cin>>E[i].from>>E[i].to>>E[i].weight;
        G[E[i].from].push_back(P(E[i].to,E[i].weight));
        G[E[i].to].push_back(P(E[i].from,E[i].weight));
    }
    vector<edge>MST= Prim(G,0);
    int total_weight=0;
    for(auto e:MST)
    {
        cout<<e.from<<" -> "<<e.to<<" : "<<e.weight<<endl;
        total_weight+=e.weight;
    }
    cout<<"Total weight: "<<total_weight<<endl;
    return 0;
}
/*
输入：
5 7
0 1 10
0 2 6
0 3 5
1 3 15
2 3 4
1 2 2
3 4 3
输出：
0 -> 3 : 5
3 -> 4 : 3
3 -> 2 : 4
2 -> 1 : 2
Total weight: 14
*/